package com.zxx.casserver.modules.oplog.aop;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.JSONObject;
import com.zxx.cascommon.base.entity.Token;
import com.zxx.cascommon.base.utils.JwtTokenUtils;
import com.zxx.casserver.modules.oplog.entity.OpLogVO;
import com.zxx.casserver.modules.oplog.service.IOpLogService;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;

/**
 * 操作日志切面
 *
 * @author: zhoukai
 * @date: 2022/7/15 15:38
 */
@Aspect
@Component
public class OpLogAspect {

    private static final String IP_UN_KNOW = "unknown";
    private final IOpLogService opLogService;

    public OpLogAspect(IOpLogService opLogService) {
        this.opLogService = opLogService;
    }

    /**
     * 根据request获取Ip
     *
     * @param request
     * @author zhoukai
     * @date 2018/4/11 下午5:37
     */
    public static String getIpAddr(HttpServletRequest request) {
        if (ObjectUtils.isEmpty(request)) {
            return IP_UN_KNOW;
        }
        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.length() == 0 || IP_UN_KNOW.equalsIgnoreCase(ip)) {
            ip = request.getHeader("X-Forwarded-For");
        }
        if (ip == null || ip.length() == 0 || IP_UN_KNOW.equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || IP_UN_KNOW.equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || IP_UN_KNOW.equalsIgnoreCase(ip)) {
            ip = request.getHeader("X-Real-IP");
        }
        if (ip == null || ip.length() == 0 || IP_UN_KNOW.equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }

    /**
     * 获取方法参数值并组装为JSONObject
     *
     * @param joinPoint
     * @return
     */
    public static JSONObject getParams(JoinPoint joinPoint) {
        //获取参数值
        Object[] args = joinPoint.getArgs();
        if (ObjectUtils.isEmpty(args)) {
            return null;
        }
        JSONObject params = new JSONObject();
        //对象接收参数
        try {
            String data = JSON.toJSONString(joinPoint.getArgs()[0]);
            params = JSON.parseObject(data);
        }
        //普通参数传入
        catch (JSONException e) {
            //获取参数名
            Signature signature = joinPoint.getSignature();
            MethodSignature methodSignature = (MethodSignature) signature;
            for (int i = 0; i < methodSignature.getParameterNames().length; i++) {
                params.put(methodSignature.getParameterNames()[i], args[i]);
            }
        }
        return params;
    }

    @Pointcut("@annotation(OpLogAnnotation)")
    public void opLogPointCut() {
    }

    @Around(value = "opLogPointCut() && @annotation(opLogAnnotation)")
    public Object collector(ProceedingJoinPoint joinPoint, OpLogAnnotation opLogAnnotation) throws Throwable {
        // 获取RequestAttributes
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        // 从获取RequestAttributes中获取HttpServletRequest的信息
        assert requestAttributes != null;
        HttpServletRequest request = (HttpServletRequest) requestAttributes.resolveReference(RequestAttributes.REFERENCE_REQUEST);
        assert request != null;

        // 从切面织入点处通过反射机制获取织入点处的方法
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        // 获取切入点所在的方法
        Method method = signature.getMethod();
        // 获取操作
        OpLogAnnotation opLogAnnotationDO = method.getAnnotation(OpLogAnnotation.class);
        // 获取请求token解析操作人ID
        String token = request.getHeader("Token");
        Long uid = 0L;
        if (!ObjectUtils.isEmpty(token)) {
            Token tokenInfo = JwtTokenUtils.parseToken(token);
            if (!ObjectUtils.isEmpty(tokenInfo)) {
                uid = tokenInfo.getUid();
            }
        }

        OpLogVO opLogVO = new OpLogVO();
        if (opLogAnnotation != null) {
            opLogVO.setModules(opLogAnnotationDO.modules());
            opLogVO.setAction(opLogAnnotationDO.action());
            opLogVO.setMsg(opLogAnnotationDO.msg());
        }
        opLogVO.setUid(uid);
        opLogVO.setOpIp(getIpAddr(request));
        //获取请求参数
        JSONObject requestJson = getParams(joinPoint);
        if (!ObjectUtils.isEmpty(requestJson)) {
            opLogVO.setMsg(opLogVO.getMsg() + ":" + requestJson.toJSONString());
        }

        opLogService.saveOpLog(opLogVO);
        return joinPoint.proceed();
    }
}
